/**
 * @author 挚爱之夕
 * @version 1.0
 * @implSpec 困难
 * 给你两个单词 word1 和 word2， 请返回将 word1 转换成 word2 所使用的最少操作数  。
 * 你可以对一个单词进行如下三种操作：
 * 插入一个字符
 * 删除一个字符
 * 替换一个字符
 * 输入：word1 = "horse", word2 = "ros"
 * 输出：3
 * 解释：
 * horse -> rorse (将 'h' 替换为 'r')
 * rorse -> rose (删除 'r')
 * rose -> ros (删除 'e')
 * @since 2023-09-06 17:59
 */
public class _072编辑距离 {
    public static void main(String[] args) {
        String word1 = "horse", word2 = "ros";
        System.out.println(new _072编辑距离().minDistance(word1, word2));
    }
    public int minDistance(String word1, String word2) {
        int n = word1.length(), m = word2.length();
        //有空串
        if (n * m == 0) return n + m;
        //dp[i][j] 表示使 word1[0,i - 1] 和 word2[0,j-1] 相同，所使用的最少操作数
        int[][] dp = new int[n + 1][m + 1];
        //临界处理
        for (int i = 0; i <= n; i++) {
            dp[i][0] = i;
        }
        for (int j = 0; j <= m; j++) {
            dp[0][j] = j;
        }

        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= m; j++) {
                //word1 末尾添加一个字符， word1 末尾删除一个字符
                dp[i][j] = Math.min(dp[i][j - 1] + 1, dp[i - 1][j] + 1);
                //word1 替换末尾字符(末尾字符不相同才需要替换)
                int cnt = word1.charAt(i - 1) == word2.charAt(j - 1) ? dp[i - 1][j - 1] : dp[i - 1][j - 1] + 1;
                dp[i][j] = Math.min(dp[i][j], cnt);
            }
        }
        return dp[n][m];
    }


    public int minDistance1(String word1, String word2) {
        int n = word1.length(), m = word2.length();
        if (n * m == 0) return n + m;

        int[][] dp = new int[n + 1][m + 1];

        for (int i = 0; i <= n; i++) {
            dp[i][0] = i;
        }
        for (int j = 0; j <= m; j++) {
            dp[0][j] = j;
        }

        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= m; j++) {
                if (word1.charAt(i - 1) == word2.charAt(j - 1)) {
                    dp[i][j] = min(dp[i][j - 1] + 1, dp[i - 1][j] + 1, dp[i - 1][j - 1]);
                } else {
                    dp[i][j] = min(dp[i][j - 1] + 1, dp[i - 1][j] + 1, dp[i - 1][j - 1] + 1);
                }
            }
        }
        return dp[n][m];
    }

    private int min(int... nums) {
        int res = Integer.MAX_VALUE;
        for (int num : nums) {
            res = Math.min(res, num);
        }
        return res;
    }
}
